package com.meshnetics.gb.stack.mac.primitives;

import com.meshnetics.gb.stack.core.event.StackEventType;
import com.meshnetics.gb.stack.core.event.StackRequest;
import com.meshnetics.gb.stack.mac.RadioMACStackLayer;
import com.meshnetics.gb.stack.mac.type.Capability;
import com.meshnetics.gb.stack.mac.type.DataAddress;
import com.meshnetics.gb.type.impl.ByteUtils;
import com.meshnetics.gb.type.impl.zcl.Bool;
import com.meshnetics.gb.type.impl.zcl.TypeBool;
import com.meshnetics.gb.type.impl.zcl.TypeUInt;
import com.meshnetics.gb.type.impl.zcl.UInt;

import java.nio.ByteBuffer;

/**
 * WRITE DESCRIPTION HERE
 *
 * @author AKovylin
 */
public class MACAssociateRequest extends StackRequest implements MACCommand, MACReplyAwaited {
    public static final byte CODE = 0x45;

    private final UInt logicalChannel;
    private final DataAddress coordAddr;
    private final Capability capabilityInfo;
    private final Bool securityEnable;

    public MACAssociateRequest(int logicalChannel, DataAddress coordAddr,
                               Capability capabilityInfo, boolean securityEnable) {
        this((byte) (logicalChannel & 0xff), coordAddr, capabilityInfo, securityEnable);
    }

    public MACAssociateRequest(byte logicalChannel, DataAddress coordAddr,
                               Capability capabilityInfo, boolean securityEnable) {
        this(new Byte(logicalChannel), coordAddr, capabilityInfo, Boolean.valueOf(securityEnable));
    }

    public MACAssociateRequest(Byte logicalChannel, DataAddress coordAddr,
                               Capability capabilityInfo, Boolean securityEnable) {
        this((UInt) TypeUInt.UINT_8.fromObject(logicalChannel), coordAddr, capabilityInfo,
                (Bool) TypeBool.BOOLEAN.fromObject(securityEnable));
    }

    public MACAssociateRequest(UInt logicalChannel, DataAddress coordAddr,
                               Capability capabilityInfo, Bool securityEnable) {
        super("macAssociateRequest", StackEventType.LME_TYPE);
        if (logicalChannel == null) {
            throw new NullPointerException("logicalChannel is null");
        }
        if (coordAddr == null) {
            throw new NullPointerException("coordAddr is null");
        }
        if (capabilityInfo == null) {
            throw new NullPointerException("capabilityInfo is null");
        }
        if (securityEnable == null) {
            throw new NullPointerException("securityEnable is null");
        }
        if (coordAddr.isNoAddress()) {
            throw new IllegalArgumentException("invalid coordAddr, must contain actual address of Coordinator");
        }
        int check = ((Number) logicalChannel.toObject()).intValue();
        if (check < 0 || check > 0x1a) {
            throw new IllegalArgumentException("invalid logicalChannel, must be in range 0x00-0x1a");
        }
        this.logicalChannel = logicalChannel.convert(TypeUInt.UINT_8);
        this.coordAddr = coordAddr;
        this.capabilityInfo = capabilityInfo;
        this.securityEnable = securityEnable;
    }

    public UInt getLogicalChannelType() {
        return logicalChannel;
    }

    public Byte getLogicalChannel() {
        return (Byte) logicalChannel.toObject();
    }

    public DataAddress getCoordAddr() {
        return coordAddr;
    }

    public Capability getCapabilityInfo() {
        return capabilityInfo;
    }

    public Bool isSecurityEnableType() {
        return securityEnable;
    }

    public Boolean isSecurityEnable() {
        return (Boolean) securityEnable.toObject();
    }

    public byte getCode() {
        return CODE;
    }

    public int getSize(RadioMACStackLayer layer) {
        return 1 + coordAddr.getDataSize() + 2;
    }

    public void serialize(ByteBuffer bb, RadioMACStackLayer layer) {
        ByteUtils.ensureNotNull(bb);
        logicalChannel.serialize(bb);
        coordAddr.serialize(bb);
        capabilityInfo.serialize(bb);
        securityEnable.serialize(bb);
    }

    public String toString() {
        return getName() + '(' + logicalChannel + ',' + coordAddr + ',' + capabilityInfo + ',' + securityEnable + ')';
    }
}
